function result = fturns(y,in)
% PURPOSE: finds turning points in a time-series
%---------------------------------------------------
% USAGE: result = fturns(y,in)
% where:  y = an (nobs x 1) time-series vector
%        in = a structure variable with options
%          in.but,  # of down-periods before an upturn  (default = 4)
%          in.aut,  # of up-periods   after  an upturn  (default = 1)
%          in.bdt,  # of up-periods   before a downturn (default = 4)
%          in.adt,  # of down-periods after  a downturn (default = 1)
%          in.seq,  1 = sequence inequality,    default = 1 
%                   0 = simple inequaltiy 
%          in.eq    1 = inequality with <=, >=, default = 1
%                   0 = strict inequalty <, >
%   e.g. in.seq=0, in.eq=1 in.but = 3, in.aut = 1 would define:
%   y(t-3), y(t-2), y(t-1), >= y(t)     [but=3, eq=1, seq=0]
%   and y(t+1) > y(t) as UT             [aut=1]
%   and y(t+1) <=  y(t) as NUT          
%
%   e.g. in.seq=0, in.eq=1 in.bdt = 3, in.adt = 2 would define:
%   y(t-3), y(t-2), y(t-1), <= y(t)     [bdt=3, eq=1, seq=0]
%   and y(t+2), y(t+1) < y(t) as DT     [adt=2]
%   and y(t+2), y(t+1) >= y(t) as NDT   
%
%   e.g. in.seq=1, in.eq=1, in.but = 3, in.aut = 1 would define:
%   y(t-3) >= y(t-2) >= y(t-1) >= y(t)  [but=3, eq=1, seq=1]
%   and y(t+1) > y(t) as UT             [aut=1]
%   and y(t+1) <=  y(t) as NUT          
%
%   e.g. in.seq=1, in.eq=0, in.bdt = 3, in.adt = 2 would define:
%   y(t-3) < y(t-2) < y(t-1) < y(t)     [bdt=3, eq=0, seq=1]
%   and y(t+2) > y(t+1) < y(t) as DT    [adt=2]
%   and y(t+2) >= y(t+1) >= y(t) as NDT 
%---------------------------------------------------
% RETURNS:
%        results = a structure variable
%        results.ut  = (nobs x 1) vector with 1 = UT periods
%        results.dt  = (nobs x 1) vector with 1 = DT periods
%        results.nut = (nobs x 1) vector with 1 = NUT periods
%        results.ndt = (nobs x 1) vector with 1 = NDT periods
%        results.y   = time-series vector input
% (NUT = no upturn, NDT = no downturn)        
%--------------------------------------------------
% SEE ALSO: plt_turns (which will plot turning points)
%--------------------------------------------------
% REFERENCES:  Wecker, William E.  (1979), 'Predicting the Turning Points of 
% a Time Series,' Journal of Business, 55, pp.  57-85.

% written by:
% James P. LeSage, Dept of Economics
% Texas State University-San Marcos
% 601 University Drive
% San Marcos, TX 78666
% jlesage@spatial-econometrics.com

if ~isstruct(in)
error('fturns: structure variable needed for input options');
end;

% set up defaults
but = 4; aut = 1; bdt = 4; adt = 1;
eq = 1; seq=1;
% parse input options
fields = fieldnames(in);
nf = length(fields);
for i=1:nf
    if strcmp(fields{i},'but')
        but = in.but; 
    elseif strcmp(fields{i},'aut')
        aut = in.aut;
    elseif strcmp(fields{i},'bdt');
        bdt = in.bdt;
    elseif strcmp(fields{i},'adt');
        adt = in.adt;
    elseif strcmp(fields{i},'seq');
        seq = in.seq;
    elseif strcmp(fields{i},'eq');
        eq = in.eq;        
    end;
end;

[nobs junk] = size(y);
result.meth = 'fturns';
result.ut  = zeros(nobs,1);
result.dt  = zeros(nobs,1);
result.nut = zeros(nobs,1);
result.ndt = zeros(nobs,1);
result.y = y;

start = max(bdt,but);
send = max(adt,aut);

switch(seq)


case {0} % non-sequential definition

for i=start+1:nobs-send;
    
% find y(i-bdt,1), y(i-bdt-1), y(i-bdt-2), y(i-bdt-3), ... <= y(i)
% which is the condition for a downturn
% find y(i+adt), y(i+adt-1), ... , y(i+1) <= y(i) 
% which is a downturn
% else we have ndt
    
    cntd = 0;
  for j=1:bdt
   if eq == 1
    if y(i-j,1) <= y(i,1)
        cntd = cntd + 1;
    end; % end of if
   elseif eq == 0
    if y(i-j,1) < y(i,1)
        cntd = cntd + 1;
    end; % end of if
   else
    error('fturns: wrong eq setting');
   end;
  end; % end of for j

 if cntd == bdt % conditions right for a downturn
    check = 0;
    for k=1:adt
        if y(i+k,1) < y(i,1)
            check = check + 1;
        end; % end of if
    end; % end of for k
    if check == adt    
     result.dt(i,1) = 1;
    else
     result.ndt(i,1) = 1;
    end; % end of if
 end; % end of if cntd

% find y(i-but,1), y(i-but-1), y(i-but-2), y(i-but-3), ... >= y(i)
% which is the condition for a upturn
% find y(i+aut), y(i+aut-1), ..., y(i+1) <= y(i) 
% which is an upturn
% else we have nut

     cntu = 0;
  for j=1:but
   if eq == 1
    if y(i-j,1) >= y(i,1)
        cntu = cntu + 1;
    end; % end of if
   elseif eq == 0
    if y(i-j,1) > y(i,1)
        cntu = cntu + 1;
    end; % end of if  
   else
    error('fturns: wrong eq setting');
   end;
  end; % end of for j
 if cntu == but % conditions right for an upturn   
    check = 0;
    for k=1:aut
        if y(i+k,1) > y(i,1)
            check = check + 1;
        end; % end of if
    end; % end of for k
    if check == aut    
     result.ut(i,1) = 1;
    else
     result.nut(i,1) = 1;
    end; % end of if
 end; % end of if cntu

end; % end of for i loop

case {1}

for i=start+1:nobs-send;
    
% find y(i-bdt,1) <= y(i-bdt-1) <= y(i-bdt-2) <= y(i-bdt-3) <= ... <= y(i)
% which is the condition for a downturn
% find y(i+adt) <= y(i+adt-1) <= ... <= y(i+1) <= y(i) 
% which is a downturn
% else we have ndt
    
    cntd = 0;
  for j=0:bdt-1
   if eq == 1
    if y(i-j-1,1) <= y(i-j,1)
        cntd = cntd + 1;
    end; % end of if
   elseif eq == 0
    if y(i-j-1,1) < y(i-j,1)
        cntd = cntd + 1;
    end; % end of if
   else
    error('fturns: wrong eq setting');
   end;
  end; % end of for j

 if cntd == bdt % conditions right for a downturn
    check = 0;
    for k=0:adt-1
        if y(i+k+1,1) < y(i+k,1)
            check = check + 1;
        end; % end of if
    end; % end of for k
    if check == adt    
     result.dt(i,1) = 1;
    else
     result.ndt(i,1) = 1;
    end; % end of if
 end; % end of if cntd

% find y(i-but,1) >= y(i-but-1) >= y(i-but-2) >= y(i-but-3) >= ... >= y(i)
% which is the condition for a upturn
% find y(i+aut) <= y(i+aut-1) <= ... <= y(i+1) <= y(i) 
% which is an upturn
% else we have nut

     cntu = 0;
  for j=0:but-1
   if eq == 1
    if y(i-j-1,1) >= y(i-j,1)
        cntu = cntu + 1;
    end; % end of if
   elseif eq == 0
    if y(i-j-1,1) > y(i-j,1)
        cntu = cntu + 1;
    end; % end of if
   else
    error('fturns: wrong eq setting');
   end;
  end; % end of for j
 if cntu == but % conditions right for an upturn   
    check = 0;
    for k=0:aut-1
        if y(i+k+1,1) > y(i+k,1)
            check = check + 1;
        end; % end of if
    end; % end of for k
    if check == aut    
     result.ut(i,1) = 1;
    else
     result.nut(i,1) = 1;
    end; % end of if
 end; % end of if cntu

end; % end of for i loop

% end of non-sequential definition


otherwise
error('fturns: wrong in.seq setting');

end; % end of switch







